package com.geekhalo.lego.plugin.sync;

import com.geekhalo.lego.plugin.support.util.Utils;
import com.intellij.ide.util.ClassFilter;
import com.intellij.ide.util.TreeClassChooser;
import com.intellij.ide.util.TreeClassChooserFactory;
import com.intellij.openapi.command.WriteCommandAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import org.apache.commons.lang3.StringUtils;
import org.jetbrains.annotations.Nullable;

import javax.swing.*;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import static com.geekhalo.lego.plugin.support.util.Utils.hasImports;

public class FieldSyncDialog extends DialogWrapper {
    private static final List<String> FILTER_FIELDS = Arrays.asList("vsn","createAt", "updateAt", "deleteAt");
    private JPanel contentPane;
    private JTextField targetClass;
    private JButton selectTargetClassBtn;
    private DefaultTableModel tableModel;
    private JTable showPropertiesTable;
    private JButton syncBtn;
    private JCheckBox hidenSync;

    private final List<String> targetClsFields = new ArrayList<String>();
    private final Project project;
    private final PsiClass psiClass;
    private final List<PsiField> fields;

    public FieldSyncDialog(Project project, PsiField field) {
       this(project, field.getContainingClass(), new PsiField[]{field});
    }

    public FieldSyncDialog(Project project, PsiClass psiClass){
        this(project, psiClass, psiClass.getAllFields());
    }

    public FieldSyncDialog(Project project, PsiClass psiClass, PsiField[] fields) {
        super(project);
        this.project = project;
        this.psiClass = psiClass;
        this.fields = Arrays.asList(fields);
        setModal(true);

        initComponent();
        init();
    }

    @Override
    protected void doOKAction(){
        super.doOKAction();
    }

    @Override
    public void doCancelAction(){
        super.doCancelAction();
    }

    private void initComponent() {
        this.selectTargetClassBtn.addActionListener(e->{
            TreeClassChooserFactory factory = TreeClassChooserFactory.getInstance(project);
            // 设置过滤条件，只选择 public 类型的类
            ClassFilter classFilter = psiClass -> psiClass.getModifierList().hasExplicitModifier(PsiModifier.PUBLIC);
            // 弹出选择类的窗口
            TreeClassChooser chooser = factory.createWithInnerClassesScopeChooser(
                    "选择目标类",
                    GlobalSearchScope.allScope(project),
                    classFilter,
                    null);
            chooser.showDialog();
            // 获取用户选择的类
            PsiClass selectedClass = chooser.getSelected();
            // 如果用户选择了类，则在控制台输出类名
            if (selectedClass != null) {
                updateTarget(selectedClass.getQualifiedName());
                updateProperties();
            }
        });

        this.hidenSync.addActionListener(new ActionListener() {

            @Override
            public void actionPerformed(ActionEvent e) {
                updateTarget(null);
                updateProperties();
            }
        });

        this.tableModel = new DefaultTableModel(){
            @Override
            public boolean isCellEditable(int row, int column) {
                if(column == 0){
                    return true;
                }
                return false;
            }

            @Override
            public Class getColumnClass(int column) {
                if (column == 0) {
                    return Boolean.class;
                }
                return String.class;
            }
        };

        this.tableModel.addColumn("是否同步");
        this.tableModel.addColumn("属性信息");

        this.showPropertiesTable.setModel(tableModel);
        TableColumn firstColumn = showPropertiesTable.getColumnModel()
                .getColumn(0);
        firstColumn.setMinWidth(3);
        firstColumn.setPreferredWidth(3);
        firstColumn.setWidth(3);

        String name = this.psiClass.getQualifiedName();
        String viewName = Utils.createViewByAgg(name);
        updateTarget(viewName);
        updateProperties();

        this.syncBtn.addActionListener(e -> syncFields());

    }

    private void updateTarget(String name){
        if (name == null){
            name = this.targetClass.getText();
        }
        if (StringUtils.isEmpty(name)){
            return;
        }
        GlobalSearchScope scope = GlobalSearchScope.allScope(this.project);
        JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(this.project);
        PsiClass className = psiFacade.findClass(name, scope);
        if (className != null){
            this.targetClass.setText(className.getQualifiedName());
            this.targetClsFields.clear();
            for (PsiField field : className.getAllFields()){
                this.targetClsFields.add(field.getName());
            }
        }
    }


    private void syncFields() {
        List<PsiField> syncFields = new ArrayList<>();
        for (int row = 0; row < this.tableModel.getRowCount(); row ++){
            Boolean isChecked = (Boolean) tableModel.getValueAt(row, 0);
            if (isChecked){
                Object valueAt = tableModel.getValueAt(row, 1);
                TableValue value = (TableValue) valueAt;
                syncFields.add(value.field);
            }
        }
        GlobalSearchScope scope = GlobalSearchScope.allScope(this.project);
        JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(this.project);
        PsiClass target = psiFacade.findClass(this.targetClass.getText(), scope);

        JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(project);
        PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(project);

        WriteCommandAction.runWriteCommandAction(project, ()->{
            // 将 import 语句添加到 PsiJavaFile 的 import 列表中
            PsiJavaFile javaFile = (PsiJavaFile) target.getContainingFile();
            PsiImportList importList = javaFile.getImportList();

            for (PsiField field: syncFields){
                {// 添加字段
                    PsiField fieldToAdd = elementFactory.createField(field.getName(), field.getType());
                    target.add(fieldToAdd);
                }
                { // 导入 Import
                    PsiType type = field.getType();
                    if (type instanceof PsiClassType) {
                        PsiClassType classType = (PsiClassType) type;
                        PsiClass resolvedClass = classType.resolve();
                        if (resolvedClass != null) {
                            if (resolvedClass!=null && !hasImports(importList, resolvedClass)) {
                                importList.add(elementFactory.createImportStatement(resolvedClass));
                            }
                        }
                        for (PsiType paramType : classType.getParameters()) {
                            if (paramType instanceof PsiClassType) {
                                PsiClass resolvedClass2 = ((PsiClassType) paramType).resolve();
                                if (resolvedClass2 != null && !hasImports(importList, resolvedClass2)) {
                                    importList.add(elementFactory.createImportStatement(resolvedClass2));
                                }
                            }
                        }
                    }
                }

            }

        });

        Messages.showMessageDialog("同步成功", "Warn", null);
        updateTarget(null);
        updateProperties();
    }

    private void updateProperties() {
        showPropertiesTable.clearSelection();
        tableModel.setRowCount(0);
        for (PsiField field : this.fields){
            if (accept(field)){
                JCheckBox jCheckBox = new JCheckBox();
                jCheckBox.setSelected(true);

                TableValue tableValue = new TableValue(field);

                this.tableModel.addRow(new Object[]{true, tableValue});
            }
        }
    }

    private boolean accept(PsiField field) {
        PsiAnnotation annotation = field.getAnnotation("javax.persistence.Transient");
        if (annotation != null) {
            return false;
        }
        if (!this.hidenSync.isSelected() && FILTER_FIELDS.contains(field.getName())){
            return false;
        }
        return !this.targetClsFields.contains(field.getName());
    }

    @Override
    protected @Nullable JComponent createCenterPanel() {
        return this.contentPane;
    }

    class TableValue {
        private final PsiField field;

        TableValue(PsiField field) {
            this.field = field;
        }

        @Override
        public String toString() {

            String type = this.field.getType().getPresentableText();
            StringBuilder stringBuilder = new StringBuilder();
            stringBuilder.append(type)
                    .append(" ")
                    .append(this.field.getName());
            return stringBuilder.toString();
        }
    }
}
